
#ifndef GSLMINIMIZERWRAPPER_H

#include <gsl_ext/gsl_ext_multimin.h>

#include <gsl/gsl_multimin.h>
#include <stdexcept>
#include <string>

class GSLFunctionWrapper;

using namespace std;

/// Defines the interface for GSL/GSL++ minimizer wrappers.
/**
 * This class defines the interface of C++ wrappers 
 * for GSL/GSL++ minimizer objects. This 
 * high-level interface provides a more convenient 
 * way to access the GSL/GSL++ minimizers that are 
 * written in C.
 */
class GSLMinimizerWrapper
{
public:
  /// Defines the types for minimizers using \f$C^0\f$, \f$C^1\f$ and \f$C^2\f$ functions.
  enum Type { F, FDF, FD2F };
  
  GSLMinimizerWrapper();
  
  virtual ~GSLMinimizerWrapper() { }
  
  /// Frees the memory associated with the wrapped minimizer object.
  virtual void destroyWrappedObject() = 0;
  
  /// Returns \f$\|\mathbf{x}_{k+1}-\mathbf{x}_{k}\|.\f$
  virtual gsl_vector *dx() const = 0;
  
  /// Returns \f$f(\mathbf{x}_{k})\f$.
  virtual double f() const = 0;
  
  /// Returns the dimension of the wrapped minimizer object.
  virtual int getN() const = 0;
  
  /// Returns the name of the minimization algorithm.
  virtual string getName() const = 0;
  
  /// Returns the number of iterations since the creation of this wrapper object.
  int getNumIter() const { return numIter_; }
  
  /// Returns the number of iterates the algorithm generates each step.
  virtual int getNumIteratesPerStep() = 0;
  
  virtual void *getState() const = 0;
    
  /// Returns the type of the wrapped minimizer object (F, FDF or FD2F).
  virtual Type getType() const = 0;
    
  /// Returns \f$\nabla f(\mathbf{x}_{k})\f$
  virtual gsl_vector *gradient() const = 0;
  
  /// Returns \f$\mathbf{H}_{f}(\mathbf{x}_{k})\f$
  virtual gsl_matrix *Hessian() const = 0;
    
  /// Carries out one iteration step and increases the iteration counter.
  int iterate();
    
  /// Returns \f$\mathbf{x}_{k}\f$.
  virtual gsl_vector *x() const = 0;
protected:
  /// Carries out one iteration step.
  virtual int iterate_() = 0;
private:
  /// the number of iterations since the creation of this wrapper object
  int numIter_;
};

/// A utility class for GSL/GSL++ minimizer wrappers.
template < typename T > class GSLMinimizerWrapperT : public GSLMinimizerWrapper
{
public:
  GSLMinimizerWrapperT(T *m):minimizer_(m) { }

  virtual ~GSLMinimizerWrapperT() { }
  
  virtual gsl_vector *dx() const { throw runtime_error("unsupported operation"); }
  
  int getN() const { return minimizer_->x->size; }
  
  void *getState() const { return minimizer_->state; }

  gsl_vector *x() const { return minimizer_->x; }
protected:
  T *minimizer_;
};

/// Wraps the functionality implemented in gsl_multimin_fminimizer.
class GSLMinimizerWrapper_f : public GSLMinimizerWrapperT< gsl_multimin_fminimizer >
{
public:
  GSLMinimizerWrapper_f(gsl_multimin_fminimizer *m);
  
  void destroyWrappedObject();
  
  double f() const;
  
  GSLMinimizerWrapper::Type getType() const;
  
  string getName() const;
  
  int getNumIteratesPerStep() { return getN() + 1; }
  
  gsl_vector *gradient() const;
  
  gsl_matrix *Hessian() const;
  
  void set(const GSLFunctionWrapper &f,
           const gsl_vector *x,
           const gsl_vector *step_size);
  
  /// Returns the current simplex size.
  double size() const;
protected:
  int iterate_();
};

/// Wraps the functionality implemented in gsl_multimin_fdfminimizer.
class GSLMinimizerWrapper_fdf : public GSLMinimizerWrapperT< gsl_multimin_fdfminimizer >
{
public:
  GSLMinimizerWrapper_fdf(gsl_multimin_fdfminimizer *m);
  
  void destroyWrappedObject();
  
  gsl_vector *dx() const;
  
  double f() const;
    
  GSLMinimizerWrapper::Type getType() const;
    
  string getName() const;
  
  int getNumIteratesPerStep() { return 1; }
    
  gsl_vector *gradient() const;
  
  gsl_matrix *Hessian() const;
    
  void set(const GSLFunctionWrapper &f, 
           const gsl_vector *x, 
           double step_size, 
           double tol);
protected:
  int iterate_();
};

/// Wraps the functionality implemented in gsl_ext_multimin_fd2fminimizer.
class GSLMinimizerWrapper_fd2f : public GSLMinimizerWrapperT< gsl_ext_multimin_fd2fminimizer >
{
public:
  GSLMinimizerWrapper_fd2f(gsl_ext_multimin_fd2fminimizer *m);
  
  void destroyWrappedObject();
  
  gsl_vector *dx() const;
  
  double f() const;
  
  string getName() const;
  
  int getNumIteratesPerStep() { return 1; }
  
  GSLMinimizerWrapper::Type getType() const;
  
  gsl_vector *gradient() const;
  
  gsl_matrix *Hessian() const;
  
  void set(const GSLFunctionWrapper &f, 
           const gsl_vector *x, 
           double step_size, 
           double tol);
protected:
  int iterate_();
};

#define GSLMINIMIZERWRAPPER_H

#endif
